/**
 * Class for parsing the HTTP request headers and such.
 *
 * @author micha
 *
 */

package tomkitty.server;

import tomkitty.turdlet.*;
import tomkitty.util.*;
import java.net.*;
import java.util.*;

public class HttpRequestParser {

	private String method;
	private String version;
	private String uri;
	private boolean valid = true;
	private Hashtable<String, String[]> fields = 
		new Hashtable<String, String[]>();


	public String getMethod() {
		return method;
	}

	public String getVersion() {
		return version;
	}

	public String getURI() {
		return uri;
	}

	public Hashtable<String, String[]> getFields() {
		return fields;
	}

	public boolean isValid() {
		return valid;
	}

	public HttpRequestParser(String reqLine, String fieldstr) {

		//
		// parse the header fields into a hashtable that maps, for example,
		// "Host" => "localhost:8080"
		// "Accept" => "text/plain,text/html"
		//

		String[] lines = fieldstr.split("\n");
		for (int i = 0; i < lines.length; i++) {
			String[] field = lines[i].split(":", 2);
			field[0] = field[0].trim();
			field[1] = field[1].trim();
			if (field[0].length() > 0) {
				fields.put(field[0], field[1].split(","));
			}
		}

		//
		// expect, according to RFC-2616 (section 5), something of the form
		//
		// 		RequestLine = Method SP Request-URI SP HTTP-Version CRLF
		//
		// where
		//
		// 		Method = "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE" |
		// 						 "TRACE" | "CONNECT"
		//
		// 		Request-URI = "*" | absoluteURI | abs_path | authority
		//
		//		HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
		//		

		// get the request method
		String method = "";
		int i = reqLine.indexOf(' ');
		if (i > 0 && reqLine.length() > 0) {
			method = reqLine.substring(0, i);
			reqLine = reqLine.substring(i + 1);
		}
		
		if (
					method.equals("OPTIONS") || 
					method.equals("GET") || 
					method.equals("HEAD") || 
					method.equals("POST") || 
					method.equals("PUT") || 
					method.equals("DELETE") || 
					method.equals("TRACE") ||
					method.equals("CONNECT")
				) {
			this.method = method;
		} else {
			valid = false;
		}

		// get the request URI
		i = reqLine.indexOf(' ');
		if (i > 0 && reqLine.length() > 0) {
			this.uri = "http://" + fields.get("Host")[0] + reqLine.substring(0, i);
			reqLine = reqLine.substring(i + 1);
		} else {
			valid = false;
		}
		
		// get http-version
		String version = reqLine;
		String verNum  = "";
		if (version.length() > 5) {
			verNum = version.substring(5);
		}
		
		if (version.substring(0,5).equals("HTTP/") && isValidVersion(verNum)) {
			this.version = verNum;
		} else {
			valid = false;
		}

	}

	// a valid version number format is given above
	private boolean isValidVersion(String verNum) {

		int numDots = 0;

		for (int i = 0; i < verNum.length(); i++) {
			char c = verNum.charAt(i);
			if (c == '.' && i > 0) {
				if (numDots++ > 0 || i == verNum.length() - 1) {
					return false;
				}
			} else if (c < 48 || c > 57) {
				return false;
			}
		}

		return true;

	}
	
}
